#pragma once
#include <pthread.h>
#include <queue>

const int default_size = 5;

template<class T>
class BlockQueue
{
public:
    BlockQueue(int size = default_size)
    :_size(size)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_p_cond, nullptr);
        pthread_cond_init(&_c_cond, nullptr);  //第二个参数记得填
    }
    bool isempty()
    {
        return _q.size() == 0;
    }
    bool isfull()
    {
        return _q.size() == _size;
    }
    void push(const T& task) // producer
    {
        // pthread_mutex_lock(&_mutex);
        LockGuard lock(&_mutex);

        // if(!isfull())   //注意的是为满的时候，而不是不为空的时候
        // {
        //     _q.push(task);
        //     pthread_cond_signal(&_c_cond);
        // }
        while(isfull())
        {
            pthread_cond_wait(&_p_cond, &_mutex);
        }
        _q.push(task);
        pthread_cond_signal(&_c_cond);
        // pthread_mutex_unlock(&_mutex);
    }
    void pop(T* out) // consumer
    {
        // pthread_mutex_lock(&_mutex);
        LockGuard lock(&_mutex);
        // if(!isempty())                 //空的时候不弹
        // {
        //     out = &_q.top();
        //     _q.pop();
        // }
        while(isempty())
        {
            pthread_cond_wait(&_c_cond, &_mutex);
        }
        // out = &_q.front();      //???????
        *out = _q.front();
        _q.pop();
        pthread_cond_signal(&_p_cond);
        // pthread_mutex_unlock(&_mutex);
    }
    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_p_cond);
        // pthread_cond_destory(&_c_cond); //          destroy好几次这个单词写错了
        pthread_cond_destroy(&_c_cond); 
    }
private:
    std::queue<T> _q;
    int _size;
    pthread_mutex_t _mutex;

    pthread_cond_t _p_cond;
    pthread_cond_t _c_cond;
};